;;; cl-seq-tests.el --- Tests for cl-seq.el functionality  -*- lexical-binding: t; -*-

;; Copyright (C) 2015-2025 Free Software Foundation, Inc.

;; Author: Nicolas Richard <youngfrog@members.fsf.org>

;; This file is part of GNU Emacs.

;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;;; Code:

(require 'ert)
(require 'cl-seq)

(ert-deftest cl-union-test-00 ()
  "Test for https://debbugs.gnu.org/22729 ."
  (let ((str1 "foo")
        (str2 (make-string 3 ?o)))
    ;; Emacs may make two string literals eql when reading.
    (aset str2 0 ?f)
    (should (not (eql str1 str2)))
    (should (equal str1 str2))
    (should (equal (cl-union (list str1) (list str2))
                   (list str2)))
    (should (equal (cl-union (list str1) (list str2) :test 'eql)
                   (list str1 str2)))))

(defvar cl-seq--test-list nil
  "List used on `cl-seq' tests with side effects.")
(defvar cl-seq--test-list2 nil
  "List used on `cl-seq' tests with side effects.")

(defmacro cl-seq--with-side-effects (list list2 &rest body)
  "Run a test with side effects on lists; after the test restore the lists.
LIST is the value of `cl-seq--test-list' before the test.
LIST2, if non-nil, is the value of `cl-seq--test-list2' before the test.
Body are forms defining the test."
  (declare (indent 2) (debug t))
  (let ((orig (make-symbol "orig"))
        (orig2 (make-symbol "orig2")))
    `(let ((,orig (copy-sequence ,list))
           (,orig2 (copy-sequence ,list2)))
       (unwind-protect (progn ,@body)
         (setq cl-seq--test-list ,orig)
         (when ,list2
           (setq cl-seq--test-list2 ,orig2))))))

(ert-deftest cl-seq-endp-test ()
  (should (cl-endp '()))
  (should (not (cl-endp '(1 2 3))))
  (should-error (cl-endp 42) :type 'wrong-type-argument))

(ert-deftest cl-seq-reduce-test ()
  (should (equal 6 (cl-reduce #'+ '(1 2 3))))
  (should (equal 5 (cl-reduce #'+ '(1 2 3 4) :start 1 :end 3)))
  (should (equal 10 (cl-reduce #'+ '(1 2 3 4) :from-end t)))
  (should (equal 10 (cl-reduce #'+ '(1 2 3 4) :initial-value 0)))
  (should (equal 24 (cl-reduce #'* '(1 2 3 4) :initial-value 1)))
  (should (equal 0 (cl-reduce #'+ '())))
  (should (equal 0 (cl-reduce #'+ '() :initial-value 0)))
  (should (equal 1 (cl-reduce #'+ '(1))))
  (should (equal 0 (cl-reduce #'+ '() :initial-value 0))))

;; keywords supported:  :start :end
(ert-deftest cl-seq-fill-test ()
  (let* ((cl-seq--test-list '(1 2 3 4 5 2 6))
         (orig (copy-sequence cl-seq--test-list))
         (tests '((should (equal '(b b b b b b b) (cl-fill _list 'b)))
                  (should (equal '(1 2 3 4 b b b) (cl-fill _list 'b :start 4)))
                  (should (equal '(b b b b 5 2 6) (cl-fill _list 'b :end 4)))
                  (should (equal '(1 2 b b 5 2 6) (cl-fill _list 'b :start 2 :end 4)))
                  (should (equal orig (cl-fill _list 'b :end 0))))))
    (dolist (test tests)
      (let ((_list cl-seq--test-list))
        (cl-seq--with-side-effects orig nil
          test)))))

;; keywords supported:  :start1 :end1 :start2 :end2
(ert-deftest cl-seq-replace-test ()
  (let* ((cl-seq--test-list '(1 2 3 4 5 2 6))
         (cl-seq--test-list2 (make-list 6 'a))
         (orig  (copy-sequence cl-seq--test-list))
         (orig2 (copy-sequence cl-seq--test-list2))
         (tests '((should (equal '(a a a a a a 6) (cl-replace _list _list2)))
                  (should (equal '(a a a a a a 6) (cl-replace _list _list2 :start1 0)))
                  (should (equal '(a a a a a a 6) (cl-replace _list _list2 :start2 0)))
                  (should (equal orig (cl-replace _list _list2 :start1 (length _list))))
                  (should (equal orig (cl-replace _list _list2 :start2 (length _list2))))
                  (should (equal orig (cl-replace _list _list2 :end1 0)))
                  (should (equal orig (cl-replace _list _list2 :end2 0)))
                  (should (equal '(1 2 3 4 a a a) (cl-replace _list _list2 :start1 4)))
                  (should (equal '(a a a a 5 2 6) (cl-replace _list _list2 :end1 4)))
                  (should (equal '(a a 3 4 5 2 6) (cl-replace _list _list2 :start2 4)))
                  (should (equal '(a a a a 5 2 6) (cl-replace _list _list2 :end2 4)))
                  (should (equal '(1 2 a a 5 2 6) (cl-replace _list _list2 :start1 2 :end1 4)))
                  (should (equal '(a a 3 4 5 2 6) (cl-replace _list _list2 :start2 2 :end2 4))))))
    (dolist (test tests)
      (let ((_list cl-seq--test-list)
            (_list2 cl-seq--test-list2))
        (cl-seq--with-side-effects orig orig2
          test)))))

;; keywords supported:  :test :test-not :key :count :start :end :from-end
(ert-deftest cl-seq-remove-test ()
  (let ((list '(1 2 3 4 5 2 6)))
    (should (equal list (cl-remove 'foo list)))
    (should (equal '(1 3 4 5 6) (cl-remove 2 list)))
    (should (equal '(1 3 4 5 6) (cl-remove 2 list
                                           :key #'identity
                                           :test (lambda (a b) (eql a b)))))
    (should (equal '(1 2 3 4 2)   (cl-remove 4 list :test (lambda (a b) (> b a)))))
    (should (equal '(5 6)         (cl-remove 4 list :test-not (lambda (a b) (> b a)))))
    (should (equal '(1 3 5)       (cl-remove 'foo list :if #'cl-evenp)))
    (should (equal '(2 4 2 6)     (cl-remove 'foo list :if-not #'cl-evenp)))
    (should (equal '(1 2 3 4 5)   (cl-remove 'foo list :if #'cl-evenp :start 4)))
    (should (equal '(1 2 3 4 5 6) (cl-remove 2 list :start 5 :end 6)))
    (should (equal '(1 3 4 5 2 6) (cl-remove 2 list :count 1)))
    (should (equal '(1 3 4 5 2 6) (cl-remove 2 list :from-end nil :count 1)))
    (should (equal '(1 2 3 4 5 6) (cl-remove 2 list :from-end t :count 1)))))

(ert-deftest cl-remove-if-test ()
  (should (equal '(1 3) (cl-remove-if 'cl-evenp '(1 2 3 4))))
  (should (equal '(1 3) (cl-remove-if 'cl-evenp '(1 2 3 4) :count 2)))
  (should (equal '(1 3 4) (cl-remove-if 'cl-evenp '(1 2 3 4) :start 1 :end 3)))
  (should (equal '(1 3) (cl-remove-if 'cl-evenp '(1 2 3 4) :from-end t)))
  (should (equal '(2 4) (cl-remove-if 'cl-oddp '(1 2 3 4))))
  (should (equal '() (cl-remove-if 'cl-evenp '())))
  (should (equal '() (cl-remove-if 'cl-evenp '(2)))))

(ert-deftest cl-remove-if-not-test ()
  (should (equal '(2 4) (cl-remove-if-not 'cl-evenp '(1 2 3 4))))
  (should (equal '(2 4) (cl-remove-if-not 'cl-evenp '(1 2 3 4) :count 2)))
  (should (equal '(1 2 4) (cl-remove-if-not 'cl-evenp '(1 2 3 4) :start 1 :end 3)))
  (should (equal '(2 4) (cl-remove-if-not 'cl-evenp '(1 2 3 4) :from-end t)))
  (should (equal '(1 3) (cl-remove-if-not 'cl-oddp '(1 2 3 4))))
  (should (equal '() (cl-remove-if-not 'cl-evenp '())))
  (should (equal '(2) (cl-remove-if-not 'cl-evenp '(2))))
  (should (equal '(2) (cl-remove-if-not 'cl-evenp '(2) :key #'(lambda (x) (- x))))))

;; keywords supported:  :test :test-not :key :count :start :end :from-end
(ert-deftest cl-seq-delete-test ()
  (let* ((cl-seq--test-list '(1 2 3 4 5 2 6))
         (orig (copy-sequence cl-seq--test-list))
         (tests '((should (equal orig         (cl-delete 'foo _list)))
                  (should (equal '(1 3 4 5 6) (cl-delete 2 _list)))
                  (should (equal '(1 3 4 5 6) (cl-delete 2 _list
                                                         :key #'identity
                                                         :test (lambda (a b) (eql a b)))))
                  (should (equal '(1 2 3 4 2)   (cl-delete 4 _list :test (lambda (a b) (> b a)))))
                  (should (equal '(5 6)         (cl-delete 4 _list :test-not (lambda (a b) (> b a)))))
                  (should (equal '(1 3 5)       (cl-delete 'foo _list :if #'cl-evenp)))
                  (should (equal '(2 4 2 6)     (cl-delete 'foo _list :if-not #'cl-evenp)))
                  (should (equal '(1 2 3 4 5)   (cl-delete 'foo _list :if #'cl-evenp :start 4)))
                  (should (equal '(1 2 3 4 5 6) (cl-delete 2 _list :start 5 :end 6)))
                  (should (equal '(1 3 4 5 2 6) (cl-delete 2 _list :count 1)))
                  (should (equal '(1 3 4 5 2 6) (cl-delete 2 _list :from-end nil :count 1)))
                  (should (equal '(1 2 3 4 5 6) (cl-delete 2 _list :from-end t :count 1))))))
    (dolist (test tests)
      (let ((_list cl-seq--test-list))
        (cl-seq--with-side-effects orig nil
          test)))))

(ert-deftest cl-delete-if-test ()
  (let ((list (list 1 2 3 4 5)))
    (cl-delete-if 'cl-evenp list)
    (should (equal '(1 3 5) list))
    (should (equal '(1 3 5) (cl-delete-if 'cl-evenp (list 1 2 3 4 5) :start 0 :end 4)))
    (should (equal '(1 3 5) (cl-delete-if 'cl-evenp (list 1 2 3 4 5) :from-end t)))
    (should (equal '(2 4) (cl-delete-if 'cl-oddp (list 1 2 3 4 5))))
    (should (equal '() (cl-delete-if 'cl-evenp '())))
    (should (equal '() (cl-delete-if 'cl-evenp (list 2))))))

(ert-deftest cl-delete-if-not-test ()
  (let ((list (list 1 2 3 4 5)))
    (should (equal '(2 4) (cl-delete-if-not 'cl-evenp list)))
    (should (equal '() (cl-delete-if-not 'cl-evenp '())))
    (should (equal '() (cl-delete-if-not 'cl-evenp (list 1))))))

(ert-deftest cl-delete-duplicates-test ()
  (let ((list (list 1 2 3 2 1)))
    (should (equal '(3 2 1) (cl-delete-duplicates list)))
    (should (equal '() (cl-delete-duplicates '())))))

;; keywords supported:  :test :test-not :key :start :end :from-end
(ert-deftest cl-seq-remove-duplicates-test ()
  (let ((list '(1 2 3 4 5 2 6)))
    (should (equal '(1 3 4 5 2 6) (cl-remove-duplicates list)))
    (should (equal '(1 2 3 4 5 6) (cl-remove-duplicates list :from-end t)))
    (should (equal list           (cl-remove-duplicates list :start 2)))
    (should (equal list           (cl-remove-duplicates list :start 2 :from-end t)))
    (should (equal list           (cl-remove-duplicates list :end 4)))
    (should (equal '(6)           (cl-remove-duplicates list :test (lambda (a b) (< a b)))))
    (should (equal '(1 2 6)       (cl-remove-duplicates list :test (lambda (a b) (>= a b)))))
    (should (equal (cl-remove-duplicates list :test (lambda (a b) (>= a b)))
                   (cl-remove-duplicates list :test-not (lambda (a b) (< a b)))))
    (should (equal (cl-remove-duplicates list)
                   (cl-remove-duplicates list :key #'number-to-string :test #'string=)))
    (should (equal list
                   (cl-remove-duplicates list :key #'number-to-string :test #'eq)))))

;; keywords supported:  :test :test-not :key :count :start :end :from-end
(ert-deftest cl-seq-substitute-test ()
  (let ((list '(1 2 3 4 5 2 6)))
    (should (equal '(1 b 3 4 5 b 6) (cl-substitute 'b 2 list)))
    (should (equal list (cl-substitute 'b 2 list :start (length list))))
    (should (equal list (cl-substitute 'b 2 list :end 0)))
    (should (equal '(1 2 3 4 5 b 6) (cl-substitute 'b 2 list :start 2)))
    (should (equal '(1 b 3 4 5 2 6) (cl-substitute 'b 2 list :end 2)))
    (should (equal list (cl-substitute 'b 2 list :start 2 :end 4)))
    (should (equal '(1 b 3 4 5 2 6) (cl-substitute 'b 2 list :count 1)))
    (should (equal '(1 2 3 4 5 b 6) (cl-substitute 'b 2 list :count 1 :from-end t)))
    (should (equal list             (cl-substitute 'b 2 list :count -1)))
    (should (equal '(1 b 3 4 5 b 6) (cl-substitute 'b "2" list :key #'number-to-string
                                                   :test #'string=)))
    (should (equal (cl-substitute 'b 2 list)
                   (cl-substitute 'b 2 list :test #'eq)))
    (should (equal '(1 2 b b b 2 b) (cl-substitute 'b 2 list :test (lambda (a b) (< a b)))))
    (should (equal '(b b 3 4 5 b 6) (cl-substitute 'b 2 list :test (lambda (a b) (>= a b)))))
    (should (equal list             (cl-substitute 'b 99 list :test (lambda (a b) (< a b)))))
    (should (equal (cl-substitute 'b 2 list :test (lambda (a b) (>= a b)))
                   (cl-substitute 'b 2 list :test-not (lambda (a b) (< a b)))))
    (should (equal '(1 2 b b b 2 b) (cl-substitute 'b nil list :if (lambda (x) (> (cl-position x list) 1)))))
    (should (equal '(1 b b b b b b) (cl-substitute 'b nil list :if (lambda (x) (> (cl-position x list :from-end t) 1)))))

    (should (equal '(b b 3 4 5 b 6) (cl-substitute 'b nil list
                                                   :if-not (lambda (x) (> (cl-position x list) 1)))))
    (should (equal '(b 2 3 4 5 2 6) (cl-substitute 'b nil list
                                                   :if-not (lambda (x) (> (cl-position x list :from-end t) 1)))))))

(ert-deftest cl-seq-substitute-if-test ()
  (let ((result (cl-substitute-if 'x #'cl-evenp '(1 2 3 4 5))))
    (should (equal result '(1 x 3 x 5))))
  (let ((result (cl-substitute-if 'x #'cl-evenp '(1 3 5))))
    (should (equal result '(1 3 5))))
  (let ((result (cl-substitute-if 'x #'(lambda (n) t) '(1 2 3 4 5))))
    (should (equal result '(x x x x x))))
  (let ((result (cl-substitute-if 'x #'cl-evenp '(1 2 3 4 5) :start 1 :end 4)))
    (should (equal result '(1 x 3 x 5))))
  (let ((result (cl-substitute-if 'x #'cl-oddp '(1 2 3 4 5) :from-end t)))
    (should (equal result '(x 2 x 4 x))))
  (let ((result (cl-substitute-if 'x (lambda (n) (= n 3)) '(1 2 3 4 5) :key 'identity)))
    (should (equal result '(1 2 x 4 5)))))

(ert-deftest cl-seq-substitute-if-not-test ()
  (let ((result (cl-substitute-if-not 'x #'cl-evenp '(1 2 3 4 5))))
    (should (equal result '(x 2 x 4 x))))
  (let ((result (cl-substitute-if-not 'x #'cl-evenp '(2 4 6))))
    (should (equal result '(2 4 6))))
  (let ((result (cl-substitute-if-not 'x #'(lambda (n) (> n 5)) '(1 2 3 4 5))))
    (should (equal result '(x x x x x))))
  (let ((result (cl-substitute-if-not 'x #'cl-evenp '(1 2 3 4 5) :start 0 :end 4)))
    (should (equal result '(x 2 x 4 5))))
  (let ((result (cl-substitute-if-not 'x #'cl-oddp '(1 2 3 4 5) :from-end t)))
    (should (equal result '(1 x 3 x 5))))
  (let ((result (cl-substitute-if-not 'x (lambda (n) (= n 3)) '(1 2 3 4 5) :key 'identity)))
    (should (equal result '(x x 3 x x)))))

(ert-deftest cl-find-if-test ()
  (let ((result (cl-find-if #'cl-evenp '(1 2 3 4 5))))
    (should (equal result 2)))
  (let ((result (cl-find-if #'(lambda (n) (> n 5)) '(1 2 3 4 5))))
    (should (equal result nil)))
  (let ((result (cl-find-if #'(lambda (n) (> n 3)) '(1 2 3 4 5 6 7))))
    (should (equal result 4)))
  (let ((result (cl-find-if #'cl-evenp '(1 2 3 4 5) :start 2)))
    (should (equal result 4)))
  (let ((result (cl-find-if #'cl-evenp '(1 2 3 4 5) :end 1)))
    (should (equal result nil)))
  (let ((result (cl-find-if #'cl-oddp '(2 4 5 6 7) :from-end t)))
    (should (equal result 7)))
  (let ((result (cl-find-if (lambda (n) (= n 4)) '(1 2 3 4 5) :key 'identity)))
    (should (equal result 4))))

(ert-deftest cl-find-if-not-test ()
  (let ((result (cl-find-if-not #'cl-evenp '(1 2 3 4 5))))
    (should (equal result 1)))
  (let ((result (cl-find-if-not #'cl-oddp '(1 3 5))))
    (should (equal result nil)))
  (let ((result (cl-find-if-not #'(lambda (n) (< n 4)) '(1 2 3 4 5 6 7))))
    (should (equal result 4)))
  (let ((result (cl-find-if-not #'cl-evenp '(1 2 3 4 5) :start 2)))
    (should (equal result 3)))
  (let ((result (cl-find-if-not #'cl-evenp '(1 2 3 4 5) :end 3)))
    (should (equal result 1)))
  (let ((result (cl-find-if-not #'cl-oddp '(2 4 6 7 8) :from-end t)))
    (should (equal result 8)))
  (let ((result (cl-find-if-not (lambda (n) (= n 4)) '(1 2 3 4 5) :key 'identity)))
    (should (equal result 1))))

;; keywords supported:  :test :test-not :key :count :start :end :from-end
(ert-deftest cl-seq-nsubstitute-test ()
  (let ((cl-seq--test-list '(1 2 3 4 5 2 6))
        (orig (copy-sequence cl-seq--test-list))
        (tests '((should (equal '(1 b 3 4 5 b 6) (cl-nsubstitute 'b 2 _list)))
                 (should (equal _list (cl-substitute 'b 2 _list :start (length _list))))
                 (should (equal _list (cl-substitute 'b 2 _list :end 0)))
                 (should (equal '(1 2 3 4 5 b 6) (cl-substitute 'b 2 _list :start 2)))
                 (should (equal '(1 b 3 4 5 2 6) (cl-substitute 'b 2 _list :end 2)))
                 (should (equal _list (cl-substitute 'b 2 _list :start 2 :end 4)))
                 (should (equal '(1 b 3 4 5 2 6) (cl-nsubstitute 'b 2 _list :count 1)))
                 (should (equal '(1 2 3 4 5 b 6) (cl-nsubstitute 'b 2 _list :count 1 :from-end t)))
                 (should (equal _list            (cl-nsubstitute 'b 2 _list :count -1)))
                 (should (equal '(1 b 3 4 5 b 6) (cl-nsubstitute 'b "2" _list :key #'number-to-string
                                                                 :test #'string=)))
                 (should (equal (cl-nsubstitute 'b 2 _list)
                                (cl-nsubstitute 'b 2 _list :test #'eq)))
                 (should (equal '(1 2 b b b 2 b) (cl-nsubstitute 'b 2 _list :test (lambda (a b) (< a b)))))
                 (should (equal '(b b 3 4 5 b 6) (cl-nsubstitute 'b 2 _list :test (lambda (a b) (>= a b)))))
                 (should (equal _list            (cl-nsubstitute 'b 99 _list :test (lambda (a b) (< a b)))))
                 (should (equal (cl-nsubstitute 'b 2 _list :test (lambda (a b) (>= a b)))
                                (cl-nsubstitute 'b 2 _list :test-not (lambda (a b) (< a b)))))
                 (should (equal '(1 2 b b b 2 b)
                                (cl-nsubstitute 'b nil _list :if (lambda (x) (> (cl-position x _list) 1)))))
                 (should (equal '(1 b b b b b b)
                                (cl-nsubstitute 'b nil _list :if (lambda (x) (> (cl-position x _list :from-end t) 1)))))
                 (should (equal '(b b 3 4 5 b 6)
                                (cl-nsubstitute 'b nil _list
                                                :if-not (lambda (x) (> (cl-position x _list) 1)))))
                 (should (equal '(b 2 3 4 5 2 6)
                                (cl-nsubstitute 'b nil _list
                                                :if-not (lambda (x) (> (cl-position x _list :from-end t) 1))))))))
    (dolist (test tests)
      (let ((_list cl-seq--test-list))
        (cl-seq--with-side-effects orig nil
          test)))))

;; keywords supported:  :test :test-not :key :start :end :from-end
(ert-deftest cl-seq-position-test ()
  (let ((list '(1 2 3 4 5 2 6)))
    (should-not (cl-position 'foo list))
    (should (= 1 (cl-position 2 list)))
    (should (= 5 (cl-position 2 list :start 5 :end 6)))
    (should (= 1 (cl-position 2 list :from-end nil)))
    (should (= 5 (cl-position 2 list :from-end t)))
    (should (cl-position 2 list :key #'identity
                         :test (lambda (a b) (eql a b))))
    (should (= 1 (cl-position "2" list :key #'number-to-string :test #'string=)))
    (should (= 5 (cl-position "2" list :key #'number-to-string :test #'string= :from-end t)))
    (should-not (cl-position "2" list :key #'number-to-string))
    (should (cl-position 5 list :key (lambda (x) (1+ (* 1.0 x x))) :test #'=))
    (should-not (cl-position 5 list :key (lambda (x) (1+ (* 1.0 x x)))))
    (should (= 1 (cl-position 5 list :key (lambda (x) (1+ (* x x))))))
    (should (= 5 (cl-position 5 list :key (lambda (x) (1+ (* x x))) :from-end t)))))

(ert-deftest cl-position-if-test ()
  (let ((result (cl-position-if #'cl-evenp '(1 2 3 4 5))))
    (should (equal result 1)))
  (let ((result (cl-position-if #'(lambda (n) (> n 5)) '(1 2 3 4 5))))
    (should (equal result nil)))
  (let ((result (cl-position-if #'(lambda (n) (> n 3)) '(1 2 3 4 5 6 7))))
    (should (equal result 3)))
  (let ((result (cl-position-if #'cl-evenp '(1 2 3 4 5) :start 2)))
    (should (equal result 3)))
  (let ((result (cl-position-if #'cl-evenp '(1 2 3 4 5) :end 1)))
    (should (equal result nil)))
  (let ((result (cl-position-if #'cl-oddp '(2 4 5 6 7) :from-end t)))
    (should (equal result 4)))
  (let ((result (cl-position-if (lambda (n) (= n 4)) '(1 2 3 4 5) :key 'identity)))
    (should (equal result 3))))

;; keywords supported:  :test :test-not :key :start :end
(ert-deftest cl-seq-count-test ()
  (let ((list '(1 2 3 4 5 2 6)))
    (should (= 2 (cl-count 2 list)))
    (should (= 1 (cl-count 2 list :start 2)))
    (should (= 1 (cl-count 2 list :end 4)))
    (should (= 0 (cl-count -5 list)))
    (should (= 0 (cl-count 2 list :start 2 :end 4)))
    (should (= 4 (cl-count 'foo list :key (lambda (x) (and (cl-evenp x) 'foo)))))
    (should (= 4 (cl-count 'foo list :test (lambda (_a b) (cl-evenp b)))))
    (should (equal (cl-count 'foo list :test (lambda (_a b) (cl-oddp b)))
                   (cl-count 'foo list :test-not (lambda (_a b) (cl-evenp b)))))))

(ert-deftest cl-count-if-test ()
  (let ((result (cl-count-if #'cl-evenp '(1 2 3 4 5))))
    (should (equal result 2)))
  (let ((result (cl-count-if #'cl-oddp '(2 4 6 8))))
    (should (equal result 0)))
  (let ((result (cl-count-if (lambda (x) t) '(1 2 3 4))))
    (should (equal result 4)))
  (let ((result (cl-count-if (lambda (x) nil) '(1 2 3 4))))
    (should (equal result 0)))
  (let ((result (cl-count-if #'(lambda (x) (> x 2)) '(1 2 3 4 5) :key 'identity)))
    (should (equal result 3)))
  (let ((result (cl-count-if #'cl-evenp '(1 2 3 4 5) :start 2)))
    (should (equal result 1)))
  (let ((result (cl-count-if #'cl-evenp '(1 2 3 4 5) :end 3)))
    (should (equal result 1)))
  (let ((result (cl-count-if #'cl-evenp '())))
    (should (equal result 0)))
  (let ((result (cl-count-if #'(lambda (x) (numberp x)) '(1 "two" 3 4 "five" 6))))
    (should (equal result 4)))
  (let ((result (cl-count-if (lambda (x) (and (numberp x) (> x 2))) '(1 2 3 4 5 6))))
    (should (equal result 4))))

(ert-deftest cl-count-if-not-test ()
  (let ((result (cl-count-if-not #'cl-evenp '(1 2 3 4 5))))
    (should (equal result 3)))
  (let ((result (cl-count-if-not #'cl-oddp '(1 3 5))))
    (should (equal result 0)))
  (let ((result (cl-count-if-not (lambda (x) t) '(1 2 3 4))))
    (should (equal result 0)))
  (let ((result (cl-count-if-not (lambda (x) nil) '(1 2 3 4))))
    (should (equal result 4)))
  (let ((result (cl-count-if-not #'(lambda (x) (> x 3)) '(1 2 3 4 5) :key 'identity)))
    (should (equal result 3)))
  (let ((result (cl-count-if-not #'cl-evenp '(1 2 3 4 5) :start 2)))
    (should (equal result 2)))
  (let ((result (cl-count-if-not #'cl-evenp '(1 2 3 4 5) :end 3)))
    (should (equal result 2)))
  (let ((result (cl-count-if-not #'cl-evenp '())))
    (should (equal result 0)))
  (let ((result (cl-count-if-not #'(lambda (x) (numberp x)) '(1 "two" 3 4 "five" 6))))
    (should (equal result 2)))
  (let ((result (cl-count-if-not (lambda (x) (and (numberp x) (> x 2))) '(1 2 3 4 5 6))))
    (should (equal result 2))))

;; keywords supported:  :test :test-not :key :start1 :end1 :start2 :end2 :from-end
(ert-deftest cl-seq-mismatch-test ()
  (let ((list '(1 2 3 4 5 2 6))
        (list2 '(1 999 2 3 4 5 2 6)))
    (should-not (cl-mismatch list list))
    (should-not (cl-mismatch list (remove 999 list2)))
    (should (= 0 (cl-mismatch list list :key #'number-to-string)))
    (should-not (cl-mismatch list list :key #'number-to-string :test #'string=))
    (should (= 1 (cl-mismatch list list2)))
    (should (= 0 (cl-mismatch list list2 :from-end t)))
    (should (= 3 (cl-mismatch '(1 2 3) list)))
    (should-not (cl-mismatch list list2 :end1 1 :end2 1))
    (should-not (cl-mismatch list list2 :start1 1 :start2 2))
    (should (= 1 (cl-mismatch list list2 :start1 1 :end1 2 :start2 4 :end2 4)))
    (should (= -1 (cl-mismatch list list2 :key #'number-to-string
                               :test (lambda (a b)
                                       (and (stringp a) (stringp b))) :from-end t)))
    (should (= 7 (cl-mismatch list list2 :key #'number-to-string
                              :test (lambda (a b)
                                      (and (stringp a) (stringp b))))))))

;; keywords supported:  :test :test-not :key :start1 :end1 :start2 :end2 :from-end
(ert-deftest cl-seq-search-test ()
  (let ((list '(1 2 3 4 5 2 6))
        (list2 '(1 999 2 3 4 5 2 6)))
    (should-not (cl-search list list2))
    (should (= 2 (cl-search list list2 :start1 1 :start2 2)))
    (should (= 4 (cl-search list list2 :start1 3)))
    (should (= 6 (cl-search list list2 :start1 5)))
    (should (= 0 (cl-search list list2 :end1 1)))
    (should (= 0 (cl-search nil list2)))
    (should (= 2 (cl-search list list2 :start1 1 :end1 2 :end2 3)))
    (should (= 0 (cl-search list list2 :test (lambda (a b) (and (numberp a) (numberp b))))))
    (should (= 0 (cl-search list list2 :key (lambda (x) (and (numberp x) 'foo))
                            :test (lambda (a b) (and (eq a 'foo) (eq b 'foo))))))
    (should (= 1 (cl-search (nthcdr 2 list) (nthcdr 2 list2))))
    (should (= 3 (cl-search (nthcdr 2 list) list2)))))

(ert-deftest cl-seq-test-bug24264 ()
  "Test for https://debbugs.gnu.org/24264 ."
  :tags '(:expensive-test)
  (let ((list  (append (make-list 8000005 1) '(8)))
        (list2 (make-list 8000005 2)))
    (should (cl-position 8 list))
    (should-not (equal '(8) (last (cl-remove 8 list))))
    (should (equal '(2 8) (last (cl-substitute 2 1 list) 2)))
    (should (equal '(2 8) (last (cl-replace list list2) 2)))
    (should (equal '(1 1) (last (cl-fill list 1) 2)))))

(ert-deftest cl-seq-bignum-eql ()
  (let ((x (+ most-positive-fixnum 1))
        (y (+ most-positive-fixnum 1)))
    (let ((l (list y)))
      (should (eq (cl-member x l) l)))
    (let ((a (list (cons y 1) (cons 2 y))))
      (should (eq (cl-assoc x a) (car a)))
      (should (eq (cl-rassoc x a) (cadr a))))))

(ert-deftest cl-sort-test ()
  (let ((result (cl-sort '(3 1 4 1 5 9 2 6 5 3 5) '<)))
    (should (equal result '(1 1 2 3 3 4 5 5 5 6 9))))
  (let ((result (cl-sort '(5 3 2 8 1 4) '>)))
    (should (equal result '(8 5 4 3 2 1))))
  (let ((result (cl-sort '("banana" "apple" "cherry") 'string<)))
    (should (equal result '("apple" "banana" "cherry"))))
  (let ((result (cl-sort '("banana" "fig" "apple" "kiwi") (lambda (x y) (< (length x) (length y))) :key 'identity)))
    (should (equal result '("fig" "kiwi" "apple" "banana"))))
  (let ((result (cl-sort (vector 3 1 4 1 5) '<)))
    (should (equal result (vector 1 1 3 4 5))))
  (let ((result (cl-sort '(1 2 3 4 5) '<)))
    (should (equal result '(1 2 3 4 5))))
  (let ((result (cl-sort '(-3 1 4 -1 -5 9) '<)))
    (should (equal result '(-5 -3 -1 1 4 9))))
  (let ((result (cl-sort '(1 2 3 4 5) (lambda (x y) (> x y)))))
    (should (equal result '(5 4 3 2 1))))
  (let ((result (cl-sort '() '<)))
    (should (equal result '())))
  (let ((result (cl-sort '("Banana" "apple" "cherry") 'string< :key 'downcase)))
    (should (equal result '("apple" "Banana" "cherry")))) )

(ert-deftest cl-stable-sort-test ()
  (let ((result (cl-stable-sort '(3 1 4 1 5 9 2 6 5 3 5) '<)))
    (should (equal result '(1 1 2 3 3 4 5 5 5 6 9))))
  (let ((result (cl-stable-sort '(5 3 2 8 1 4) '>)))
    (should (equal result '(8 5 4 3 2 1))))
  (let ((result (cl-stable-sort '("banana" "apple" "cherry") 'string<)))
    (should (equal result '("apple" "banana" "cherry"))))
  (let ((result (cl-stable-sort '("banana" "fig" "apple" "kiwi") (lambda (x y) (< (length x) (length y))) :key 'identity)))
    (should (equal result '("fig" "kiwi" "apple" "banana"))))
  (let ((result (cl-stable-sort (vector 3 1 4 1 5) '<)))
    (should (equal result (vector 1 1 3 4 5))))
  (let ((result (cl-stable-sort '(1 2 3 4 5) '<)))
    (should (equal result '(1 2 3 4 5))))
  (let ((result (cl-stable-sort '(-3 1 4 -1 -5 9) '<)))
    (should (equal result '(-5 -3 -1 1 4 9))))
  (let ((result (cl-stable-sort '(1 2 3 4 5) (lambda (x y) (> x y)))))
    (should (equal result '(5 4 3 2 1))))
  (let ((result (cl-stable-sort '() '<)))
    (should (equal result '())))
  (let ((result (cl-stable-sort '("Banana" "apple" "cherry") 'string< :key 'downcase)))
    (should (equal result '("apple" "Banana" "cherry")))) )

(ert-deftest cl-merge-test ()
  (let ((result (cl-merge 'list '(1 3 5) '(2 4 6) '<)))
    (should (equal result '(1 2 3 4 5 6))))
  (let ((result (cl-merge 'list '(1 3 3 5) '(2 3 4 6) '<)))
    (should (equal result '(1 2 3 3 3 4 5 6))))
  (let ((result (cl-merge 'list '() '(2 4 6) '<)))
    (should (equal result '(2 4 6))))
  (let ((result (cl-merge 'list '(1 3 5) '() '<)))
    (should (equal result '(1 3 5))))
  (let ((result (cl-merge 'list '() '() '<)))
    (should (equal result '())))
  (let ((result (cl-merge 'list '(1 4 6) '(2 3 5) '< :key (lambda (x) x))))
    (should (equal result '(1 2 3 4 5 6))))
  (let ((result (cl-merge 'vector (vector 1 3 5) (vector 2 4 6) '<)))
    (should (equal result (vector 1 2 3 4 5 6))))
  (let ((result (cl-merge 'list '(5 3 1) '(6 4 2) '>)))
    (should (equal result '(6 5 4 3 2 1))))
  (let ((result (cl-merge 'list '(1 2 3) '(1 2 3) '>)))
    (should (equal result '(1 2 3 1 2 3))))
  (let ((result (cl-merge 'list '(1 2) '(3 4 5) '<)))
    (should (equal result '(1 2 3 4 5))))
  (let ((result (cl-merge 'list '(4 5 6) '(1 2 3) '<)))
    (should (equal result '(1 2 3 4 5 6))))
  (let ((result (cl-merge 'list '(1 2 3) '(1.5 2.5 3.5) '<)))
    (should (equal result '(1 1.5 2 2.5 3 3.5))))
  (let ((result (cl-merge 'list '(1 2 3) '(10 20 30) '< :key (lambda (x) (* x 10)))))
    (should (equal result '(1 2 3 10 20 30)))))

(ert-deftest cl-member-test ()
  (let ((result (cl-member 'b '(a b c d))))
    (should (equal result '(b c d))))
  (let ((result (cl-member 'x '(a b c d))))
    (should (equal result nil)))
  (let ((result (cl-member 'a '(a b a c d))))
    (should (equal result '(a b a c d))))
  (let ((result (cl-member "test" '("test" "not-test" "test2") :test 'string=)))
    (should (equal result '("test" "not-test" "test2"))))
  (let ((result (cl-member 'x '(a b c d) :test-not 'eq)))
    (should (equal result '(a b c d))))
  (let ((result (cl-member 3 '(1 2 3 4 5) :key 'identity)))
    (should (equal result '(3 4 5))))
  (let ((result (cl-member 2.5 '(1 2 2.5 3) :test 'equal)))
    (should (equal result '(2.5 3))))
  (let ((result (cl-member 'a '(a a a a) :test 'eq)))
    (should (equal result '(a a a a))))
  (let ((result (cl-member 'a '())))
    (should (equal result nil)))
  (let ((result (cl-member 'b '(a c d) :test-not 'eq)))
    (should (equal result '(a c d))))
  (let ((result (cl-member 3 '(1 2 3 4 5) :key '1+)))
    (should (equal result '(2 3 4 5)))))

(ert-deftest cl-member-if-test ()
  (let ((result (cl-member-if #'cl-evenp '(1 2 3 4 5))))
    (should (equal result '(2 3 4 5))))
  (let ((result (cl-member-if #'(lambda (x) nil) '(1 2 3 4 5))))
    (should (equal result nil)))
  (let ((result (cl-member-if #'(lambda (x) t) '(1 2 3 4 5))))
    (should (equal result '(1 2 3 4 5))))
  (let ((result (cl-member-if #'(lambda (x) (= x 1)) '(1 2 3 4 5))))
    (should (equal result '(1 2 3 4 5))))
  (let ((result (cl-member-if #'(lambda (x) (and (numberp x) (cl-evenp x))) '(1 3 5 4 2))))
    (should (equal result '(4 2))))
  (let ((result (cl-member-if (lambda (x) (string= (number-to-string x) "3")) '(1 2 3 4 5) :key 'identity)))
    (should (equal result '(3 4 5))))
  (let ((result (cl-member-if #'(lambda (x) (eq x 'a)) '(a a a a))))
    (should (equal result '(a a a a))))
  (let ((result (cl-member-if #'cl-evenp '())))
    (should (equal result nil)))
  (let ((result (cl-member-if #'(lambda (x) (< x 0)) '(1 2 3 4 5))))
    (should (equal result nil)))
  (let ((result (cl-member-if (lambda (x) (and (numberp x) (<= x 2))) '(1 "two" 3 0))))
    (should (equal result '(1 "two" 3 0))))
  (let ((result (cl-member-if (lambda (x) (> x 5)) '(1 2 3 6 7 8) :key 'identity)))
    (should (equal result '(6 7 8)))))

(ert-deftest cl-member-if-not-test ()
  (let ((result (cl-member-if-not #'cl-evenp '(1 2 3 4 5))))
    (should (equal result '(1 2 3 4 5))))
  (let ((result (cl-member-if-not #'cl-evenp '(2 4 6 8 10 11))))
    (should (equal result '(11))))
  (let ((result (cl-member-if-not #'(lambda (x) (> x 5)) '(1 2 3 4 5))))
    (should (equal result '(1 2 3 4 5))))
  (let ((result (cl-member-if-not #'(lambda (x) t) '(1 2 3 4 5))))
    (should (equal result nil)))
  (let ((result (cl-member-if-not #'(lambda (x) (= x 1)) '(1 2 3 4 5))))
    (should (equal result '(2 3 4 5))))
  (let ((result (cl-member-if-not (lambda (x) (string= (number-to-string x) "2")) '(1 2 3 4 5) :key 'identity)))
    (should (equal result '(1 2 3 4 5))))
  (let ((result (cl-member-if-not #'cl-evenp '())))
    (should (equal result nil)))
  (let ((result (cl-member-if-not #'(lambda (x) (eq x 'a)) '(a a a a))))
    (should (equal result nil)))
  (let ((result (cl-member-if-not #'(lambda (x) (< x 0)) '(1 2 3 4 5))))
    (should (equal result '(1 2 3 4 5))))
  (let ((result (cl-member-if-not #'(lambda (x) (or (numberp x) (stringp x) (eq x 'b))) '(a "b" 3 nil))))
    (should (equal result '(a "b" 3 nil))))
  (let ((result (cl-member-if-not (lambda (x) (numberp x)) '(1 "two" 3 "four" 5) :key 'identity)))
    (should (equal result '("two" 3 "four" 5)))))

(ert-deftest cl-assoc-test ()
  (let ((result (cl-assoc 'b '((a . 1) (b . 2) (c . 3)))))
    (should (equal result '(b . 2))))
  (let ((result (cl-assoc 'x '((a . 1) (b . 2) (c . 3)))))
    (should (equal result nil)))
  (let ((result (cl-assoc "key" '(("key" . 1) ("not-key" . 2)) :test 'string=)))
    (should (equal result '("key" . 1))))
  (let ((result (cl-assoc 'a '((a . 1) (b . 2) (c . 3)) :test-not 'eq)))
    (should (equal result '(b . 2))))
  (let ((result (cl-assoc '2 '((1 . 'a) (2 . 'b) (3 . 'c)) :key 'identity)))
    (should (equal result '(2 . 'b))))
  (let ((result (cl-assoc 'a '((a . 1) (a . 2) (a . 3)) :test 'eq)))
    (should (equal result '(a . 1))))
  (let ((result (cl-assoc 'a '())))
    (should (equal result nil)))
  (let ((result (cl-assoc 'b '((a . 1) (b . 2) (b . 3) (c . 4)))))
    (should (equal result '(b . 2)))))

(ert-deftest cl-assoc-if-test ()
  (let ((result (cl-assoc-if #'cl-evenp '((1 . "odd") (2 . "even") (3 . "odd") (4 . "even")))))
    (should (equal result '(2 . "even"))))
  (let ((result (cl-assoc-if #'(lambda (x) (= x 5)) '((1 . "one") (2 . "two") (3 . "three")))))
    (should (equal result nil)))
  (let ((result (cl-assoc-if #'(lambda (x) (= x 1)) '((1 . "one") (2 . "two") (3 . "three")))))
    (should (equal result '(1 . "one"))))
  (let ((result (cl-assoc-if #'(lambda (x) (string= x "baz")) '((foo . 1) (bar . 2) (baz . 3)))))
    (should (equal result '(baz . 3))))
  (let ((result (cl-assoc-if (lambda (x) (and (numberp x) (> x 2))) '((1 . "one") (3 . "three") (4 . "four")))))
    (should (equal result '(3 . "three"))))
  (let ((result (cl-assoc-if #'(lambda (x) (> x 1)) '((0 . "zero") (1 . "one") (2 . "two")))))
    (should (equal result '(2 . "two"))))
  (let ((result (cl-assoc-if #'cl-evenp '())))
    (should (equal result nil)))
  (let ((result (cl-assoc-if #'(lambda (x) (eq x 'a)) '((a . "first") (a . "second") (b . "third")))))
    (should (equal result '(a . "first"))))
  (let ((result (cl-assoc-if #'(lambda (x) (and (symbolp x) (not (eq x 'b)))) '((b . "b") (c . "c") (d . "d")))))
    (should (equal result '(c . "c"))))
  (let ((result (cl-assoc-if (lambda (x) (and (listp x) (> (length x) 1))) '(((1 2) . "pair 1") ((1) . "pair 2")))))
    (should (equal result '((1 2) . "pair 1")))))

(ert-deftest cl-assoc-if-not-test ()
  (let ((result (cl-assoc-if-not #'cl-evenp '((1 . "odd") (2 . "even") (3 . "odd") (4 . "even")))))
    (should (equal result '(1 . "odd"))))
  (let ((result (cl-assoc-if-not #'(lambda (x) (> x 0)) '((1 . "one") (2 . "two") (3 . "three")))))
    (should (equal result nil)))
  (let ((result (cl-assoc-if-not #'(lambda (x) (< x 5)) '((1 . "one") (2 . "two") (3 . "three")))))
    (should (equal result nil)))
  (let ((result (cl-assoc-if-not #'(lambda (x) (= x 1)) '((1 . "one") (2 . "two") (3 . "three")))))
    (should (equal result '(2 . "two"))))
  (let ((result (cl-assoc-if-not #'(lambda (x) (string= x "baz")) '((foo . "first") (bar . "second") (baz . "third")))))
    (should (equal result '(foo . "first"))))
  (let ((result (cl-assoc-if-not (lambda (x) (and (numberp x) (> x 2))) '((1 . "one") (3 . "three") (4 . "four")))))
    (should (equal result '(1 . "one"))))
  (let ((result (cl-assoc-if-not #'(lambda (x) (symbolp x)) '((1 . "one") (b . "bee") (2 . "two")))))
    (should (equal result '(1 . "one"))))
  (let ((result (cl-assoc-if-not #'cl-evenp '())))
    (should (equal result nil)))
  (let ((result (cl-assoc-if-not #'(lambda (x) (eq x 'a)) '((a . "first") (a . "second") (b . "third")))))
    (should (equal result '(b . "third")))))

(ert-deftest cl-rassoc-test ()
  (let ((result (cl-rassoc 2 '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result (cons "two" 2))))
  (let ((result (cl-rassoc 4 '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result nil)))
  (let ((result (cl-rassoc 2 '(( "one" . 1) ("two" . 2) ("baz" . 2)) :test 'equal)))
    (should (equal result (cons "two" 2))))
  (let ((result (cl-rassoc 2 '(( "one" . 1) ("two" . 2) ("three" . 3)) :test-not 'equal)))
    (should (equal result (cons "one" 1))))
  (let ((result (cl-rassoc 1 '())))
    (should (equal result nil)))
  (let ((result (cl-rassoc 1 '(( "first" . 1) ("second" . 1) ("third" . 1)))))
    (should (equal result (cons "first" 1))))
  (let ((result (cl-rassoc 3 '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result (cons "three" 3))))
  (let ((result (cl-rassoc 'found '((( "pair 1") . 1) ( "pair 2" . 2) ( "pair 3" . 3)))))
    (should (equal result nil))))

(ert-deftest cl-rassoc-if-test ()
  (let ((result (cl-rassoc-if #'cl-evenp '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result '("two" . 2))))
  (let ((result (cl-rassoc-if #'cl-evenp '(( "one" . 1) ("three" . 3) ("five" . 5)))))
    (should (equal result nil)))
  (let ((result (cl-rassoc-if #'(lambda (x) (= x 1)) '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result '("one" . 1))))
  (let ((result (cl-rassoc-if (lambda (x) (> x 1)) '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result '("two" . 2))))
  (let ((result (cl-rassoc-if #'(lambda (x) (and (numberp x) (< x 3))) '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result '("one" . 1))))
  (let ((result (cl-rassoc-if #'cl-evenp '())))
    (should (equal result nil)))
  (let ((result (cl-rassoc-if #'(lambda (x) (> x 0)) '(( "first" . 1) ("second" . 2) ("third" . 3)))))
    (should (equal result '("first" . 1))))
  (let ((result (cl-rassoc-if #'(lambda (x) (string= (number-to-string x) "two")) '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result nil)))
  (let ((result (cl-rassoc-if #'(lambda (x) (stringp x)) '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result nil))))

(ert-deftest cl-rassoc-if-not-test ()
  (let ((result (cl-rassoc-if-not #'cl-evenp '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result '("one" . 1))))
  (let ((result (cl-rassoc-if-not #'(lambda (x) (> x 0)) '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result nil)))
  (let ((result (cl-rassoc-if-not #'(lambda (x) (< x 5)) '(( "one" . 1) ("two" . 2) ("six" . 6)))))
    (should (equal result '( "six" . 6))))
  (let ((result (cl-rassoc-if-not #'(lambda (x) (= x 1)) '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result '("two" . 2))))
  (let ((result (cl-rassoc-if-not #'(lambda (x) (> x 2)) '(( "one" . 1) ("two" . 1) ("three" . 3)))))
    (should (equal result '("one" . 1))))
  (let ((result (cl-rassoc-if-not #'(lambda (x) (and (numberp x) (< x 3))) '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result '("three" . 3))))
  (let ((result (cl-rassoc-if-not #'(lambda (x) (equal x 2)) '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result '("one" . 1))))
  (let ((result (cl-rassoc-if-not #'cl-evenp '())))
    (should (equal result nil)))
  (let ((result (cl-rassoc-if-not #'(lambda (x) (numberp x)) '(( "one" . 1) ("two" . 2) ("three" . 3)))))
    (should (equal result nil)))
  (let ((result (cl-rassoc-if-not (lambda (x) (and (listp x) (= (length x) 1))) '(((1 2) . 1) ((3 4) . 2) ((5) . 2)))))
    (should (equal result '((1 2) . 1)))))

(ert-deftest cl-intersection-test ()
  (let ((result (cl-intersection '(1 2 3 4) '(3 4 5 6))))
    (should (equal result '(4 3))))
  (let ((result (cl-intersection '(1 2) '(3 4))))
    (should (equal result '())))
  (let ((result (cl-intersection '(1 2 3) '(1 2 3))))
    (should (equal result '(1 2 3))))
  (let ((result (cl-intersection '(1 1 2 3) '(1 2 2 3 4))))
    (should (equal result '(3 2 1 1))))
  (let ((result (cl-intersection '(1 "two" 3) '(3 "two" 4))))
    (should (equal result '(3))))
  (let ((result (cl-intersection '(1 2 3) '(3 2 1) :test 'equal)))
    (should (equal result '(1 2 3))))
  (let ((result (cl-intersection '(1 2 3) '(3 4 5) :key #'identity)))
    (should (equal result '(3))))
  (let ((result (cl-intersection '() '(1 2 3))))
    (should (equal result '())))
  (let ((result (cl-intersection '() '())))
    (should (equal result '())))
  (let ((result (cl-intersection '(1 2 3 4 5) '(3 4 5 6 7 8))))
    (should (equal result '(5 4 3)))))

(ert-deftest cl-nintersection-test ()
  (let ((list1 '(1 2 3 4))
        (list2 '(3 4 5 6)))
    (let ((result (cl-nintersection list1 list2)))
      (should (equal result '(4 3)))
      (should (equal list1 '(1 2 3 4)))
      (should (equal list2 '(3 4 5 6)))))
  (let ((list1 '(1 2))
        (list2 '(3 4)))
    (let ((result (cl-nintersection list1 list2)))
      (should (equal result '()))
      (should (equal list1 '(1 2)))
      (should (equal list2 '(3 4)))))
  (let ((list1 '(1 2 3))
        (list2 '(1 2 3)))
    (let ((result (cl-nintersection list1 list2)))
      (should (equal result '(1 2 3)))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '(1 2 3)))))
  (let ((list1 '(1 1 2 2 3))
        (list2 '(2 2 3 4)))
    (let ((result (cl-nintersection list1 list2)))
      (should (equal result '(3 2 2)))
      (should (equal list1 '(1 1 2 2 3)))
      (should (equal list2 '(2 2 3 4)))))
  (let ((list1 '(1 "two" 3))
        (list2 '(3 "two" 4)))
    (let ((result (cl-nintersection list1 list2)))
      (should (equal result '(3)))
      (should (equal list1 '(1 "two" 3)))
      (should (equal list2 '(3 "two" 4)))))
  (let ((list1 '(1 2 3))
        (list2 '(3 2 1)))
    (let ((result (cl-nintersection list1 list2 :test 'equal)))
      (should (equal result '(1 2 3)))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '(3 2 1)))))
  (let ((list1 '())
        (list2 '(1 2 3)))
    (let ((result (cl-nintersection list1 list2)))
      (should (equal result '()))
      (should (equal list1 '()))
      (should (equal list2 '(1 2 3)))))
  (let ((list1 '())
        (list2 '()))
    (let ((result (cl-nintersection list1 list2)))
      (should (equal result '())))))

(ert-deftest cl-set-difference-test ()
  (let ((result (cl-set-difference '(1 2 3 4) '(3 4 5 6))))
    (should (equal result '(1 2))))
  (let ((result (cl-set-difference '(1 2 3) '())))
    (should (equal result '(1 2 3))))
  (let ((result (cl-set-difference '(1 2 3) '(1 2 3))))
    (should (equal result '())))
  (let ((result (cl-set-difference '(1 1 2 3 4) '(3 4 5))))
    (should (equal result '(1 1 2))))
  (let ((result (cl-set-difference '(1 2 3) '(3 2 4))))
    (should (equal result '(1))))
  (let ((result (cl-set-difference '(1 2 3) '(3 2 1) :test 'equal)))
    (should (equal result '())))
  (let ((result (cl-set-difference '((1 . "one") (2 . "two") (3 . "three"))
                                    '((1 . "uno") (2 . "dos"))
                                    :key 'car)))
    (should (equal result '((3 . "three")))))
  (let ((result (cl-set-difference '() '(1 2 3))))
    (should (equal result '())))
  (let ((result (cl-set-difference '(1 2 3) '())))
    (should (equal result '(1 2 3))))
  (let ((result (cl-set-difference '(1 2 3 4 5) '(3 4 5 6 7))))
    (should (equal result '(1 2))))
  (let ((list1 '(1 2 3))
        (list2 '(2 3 4)))
    (cl-set-difference list1 list2)
    (should (equal list1 '(1 2 3)))
    (should (equal list2 '(2 3 4)))))

(ert-deftest cl-nset-difference-test ()
  (let ((list1 '(1 2 3 4))
        (list2 '(3 4 5 6)))
    (let ((result (cl-nset-difference list1 list2)))
      (should (equal result '(1 2)))
      (should (equal list1 '(1 2 3 4)))
      (should (equal list2 '(3 4 5 6)))))
  (let ((list1 '(1 2 3))
        (list2 '()))
    (let ((result (cl-nset-difference list1 list2)))
      (should (equal result '(1 2 3)))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '()))))
  (let ((list1 '(1 2 3))
        (list2 '(1 2 3)))
    (let ((result (cl-nset-difference list1 list2)))
      (should (equal result '()))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '(1 2 3)))))
  (let ((list1 '(1 1 2 2 3))
        (list2 '(3 4 5)))
    (let ((result (cl-nset-difference list1 list2)))
      (should (equal result '(1 1 2 2)))
      (should (equal list1 '(1 1 2 2 3)))
      (should (equal list2 '(3 4 5)))))
  (let ((list1 '(1 2 3))
        (list2 '(3 2 4)))
    (let ((result (cl-nset-difference list1 list2)))
      (should (equal result '(1)))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '(3 2 4)))))
  (let ((list1 '(1 2 3))
        (list2 '(3 2 1)))
    (let ((result (cl-nset-difference list1 list2 :test 'equal)))
      (should (equal result '()))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '(3 2 1)))))
  (let ((list1 '())
          (list2 '(1 2 3)))
      (let ((result (cl-nset-difference list1 list2)))
        (should (equal result '()))
        (should (equal list1 '()))
        (should (equal list2 '(1 2 3)))))
  (let ((list1 '())
        (list2 '()))
    (let ((result (cl-nset-difference list1 list2)))
      (should (equal result '()))))
  (let ((list1 '(1 2 3 4 5))
        (list2 '(3 4 5 6 7)))
    (let ((result (cl-nset-difference list1 list2)))
      (should (equal result '(1 2)))
      (should (equal list1 '(1 2 3 4 5)))
      (should (equal list2 '(3 4 5 6 7))))))

(ert-deftest cl-set-exclusive-or-test ()
  (let ((result (cl-set-exclusive-or '(1 2 3) '(3 4 5))))
    (should (equal result '(1 2 4 5))))
  (let ((result (cl-set-exclusive-or '(1 2 3) '())))
    (should (equal result '(1 2 3))))
  (let ((result (cl-set-exclusive-or '() '(3 4 5))))
    (should (equal result '(3 4 5))))
  (let ((result (cl-set-exclusive-or '(1 2 3) '(1 2 3))))
    (should (equal result nil)))
  (let ((result (cl-set-exclusive-or '(1 1 2 3) '(3 4 5))))
    (should (equal result '(1 1 2 4 5))))
  (let ((result (cl-set-exclusive-or '(1 2 3) '(3 3 4 5))))
    (should (equal result '(1 2 4 5))))
  (let ((result (cl-set-exclusive-or '(1 2 3) '(3 2 4))))
    (should (equal result '(1 4))))
  (let ((result (cl-set-exclusive-or '(1 2 3) '(3 2 1) :test 'equal)))
    (should (equal result '())))
  (let ((result (cl-set-exclusive-or '() '())))
    (should (equal result '())))
  (let ((result (cl-set-exclusive-or '(1 2 3 4 5) '(3 4 5 6 7)))
        (list1 '(1 2 3 4 5))
        (list2 '(3 4 5 6 7)))
    (should (equal result '(1 2 6 7)))
    (should (equal list1 '(1 2 3 4 5)))
    (should (equal list2 '(3 4 5 6 7)))))

(ert-deftest cl-nset-exclusive-or-test ()
  (let ((list1 '(1 2 3))
        (list2 '(3 4 5)))
    (let ((result (cl-nset-exclusive-or list1 list2)))
      (should (equal result '(1 2 4 5)))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '(3 4 5)))))
  (let ((list1 '(1 2 3))
        (list2 '()))
    (let ((result (cl-nset-exclusive-or list1 list2)))
      (should (equal result '(1 2 3)))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '()))))
  (let ((list1 '(1 2 3))
        (list2 '(1 2 3)))
    (let ((result (cl-nset-exclusive-or list1 list2)))
      (should (equal result nil)))
    (should (equal list1 '(1 2 3)))
    (should (equal list2 '(1 2 3))))
  (let ((list1 '(1 1 2 2 3))
        (list2 '(3 4 5)))
    (let ((result (cl-nset-exclusive-or list1 list2)))
      (should (equal result '(1 1 2 2 4 5)))
      (should (equal list1 '(1 1 2 2 3)))
      (should (equal list2 '(3 4 5)))))
  (let ((list1 '(1 2 3))
        (list2 '(3 3 4 5)))
    (let ((result (cl-nset-exclusive-or list1 list2)))
      (should (equal result '(1 2 4 5)))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '(3 3 4 5)))))
  (let ((list1 '(1 2 3))
        (list2 '(3 2 4)))
    (let ((result (cl-nset-exclusive-or list1 list2)))
      (should (equal result '(1 4)))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '(3 2 4)))))
  (let ((list1 '(1 2 3))
        (list2 '(3 2 1)))
    (let ((result (cl-nset-exclusive-or list1 list2 :test 'equal)))
      (should (equal result '()))
      (should (equal list1 '(1 2 3)))
      (should (equal list2 '(3 2 1)))))
  (let ((list1 '())
        (list2 '(1 2 3)))
    (let ((result (cl-nset-exclusive-or list1 list2)))
      (should (equal result '(1 2 3)))
      (should (equal list1 '()))
      (should (equal list2 '(1 2 3)))))
  (let ((list1 '())
        (list2 '()))
    (let ((result (cl-nset-exclusive-or list1 list2)))
      (should (equal result '()))))
  (let ((list1 '(1 2 3 4 5))
        (list2 '(3 4 5 6 7)))
    (let ((result (cl-nset-exclusive-or list1 list2)))
      (should (equal result '(1 2 6 7)))
      (should (equal list1 '(1 2 3 4 5)))
      (should (equal list2 '(3 4 5 6 7))))))

(ert-deftest cl-subsetp-test ()
  (let ((result (cl-subsetp '(1 2) '(1 2 3 4))))
    (should (equal result t)))
  (let ((result (cl-subsetp '() '(1 2 3 4))))
    (should (equal result t)))
  (let ((result (cl-subsetp '(1 2) '())))
    (should (equal result nil)))
  (let ((result (cl-subsetp '(1 2 3) '(1 2 3))))
    (should (equal result t)))
  (let ((result (cl-subsetp '(1 1 2) '(1 2 3))))
    (should (equal result t)))
  (let ((result (cl-subsetp '(1 2) '(1 1 2 3 4))))
    (should (equal result t)))
  (let ((result (cl-subsetp '(1 "two" 3) '(3 "two" 1))))
    (should (equal result nil)))
  (let ((result (cl-subsetp '(1 2) '(2 1) :test 'equal)))
    (should (equal result t)))
  (let ((result (cl-subsetp '((1 . "one") (2 . "two")) '((1 . "uno") (2 . "dos")) :key 'car)))
    (should (equal result t)))
  (let ((result (cl-subsetp '(1 2) '(3 4 2 1) :test 'eq)))
    (should (equal result t)))
  (let ((result (cl-subsetp '((1 2) (3)) '((1 2 . "found") (3 . "found")) :key 'car)))
    (should (equal result t)))
  (let ((result (cl-subsetp '(1 2) '(1 2 3 2))))
    (should (equal result t)))
  (let ((result (cl-subsetp '() '())))
    (should (equal result t))))

(provide 'cl-seq-tests)
;;; cl-seq-tests.el ends here
